package com.huan.study.mybatis.handler;

import com.huan.study.mybatis.annotation.EncryptField;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author YanXxx
 * @ate 2022-11-03 18:01
 */
public interface EncryptHandler {

    /**
     * 加密方式抽取
     *
     * @param encryptValue 加密值
     * @return 加密后的值
     */
    String encryptMethod(String encryptValue);

    /**
     * 加密
     *
     * @param declaredFields 声明的字段
     * @param paramsObject 参数对像
     * @param <T> T
     * @return 加密后参数
     * @throws IllegalAccessException 字段不可访问异常
     */
    default <T> T encrypt(Field[] declaredFields, T paramsObject) throws IllegalAccessException {
        Set<Field> fields = getEncryptField(declaredFields);
        for (Field field : fields) {
            Object object = field.get(paramsObject);
            String encryptValue = (String) object;
            //加密时拼上唯一标识前缀“sensitive_”，执行sql语句时，
            // 如果敏感字段的值有这个前缀，说明已经加密过，不再执行加密操作。
            if (encryptValue != null) {
                //加密
                String encrypted = encryptMethod(encryptValue);
                field.set(paramsObject, encrypted);
            }

        }
        return paramsObject;
    }

    /**
     * 获取需要加密的字段
     *
     * @param declaredFields 声明的字段
     * @return 需要加密的字段
     */
    default Set<Field> getEncryptField(Field[] declaredFields) {
        //暂时只实现String类型的加密
        Set<Field> fieldSet = Arrays.stream(declaredFields).filter(field ->
                        field.isAnnotationPresent(EncryptField.class) && field.getType() == String.class)
                .collect(Collectors.toSet());
        for (Field field : fieldSet) {
            field.setAccessible(true);
        }
        return fieldSet;
    }
}
